package com.cc.service.core;

import com.cc.config.YamlOtherConfiguration;
import com.cc.pojo.file.BuiderAbstract;
import com.cc.pojo.file.FilePathAndClassName;
import com.cc.pojo.tablestruct.LibaryProperties;
import com.cc.utils.LibaryReadTable;
import com.cc.utils.beanUtil.BeanUtils;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

/**
 * @author c.c
 * @Description 核心模板
 * @since 2023/3/30
 */
public abstract class GenerateAbstract implements GenerateInterface {

  //生成路径(通过application.yaml里的createAddress来确定)
  private static final String CREAT_ADDRESS = BeanUtils.getBean(YamlOtherConfiguration.class).getCreateAddress();

  //java文件临时生成路径
  private static final HashMap<String, String> PATH_PACKAGE_MAP = new HashMap<>();

  //整个库的表结构
  private static List<LibaryProperties> LIBARY_PROPERTIES;

  @Deprecated
  private static final Properties properties = new Properties();

  static {
    try {
      //获取数据库信息
      LIBARY_PROPERTIES = LibaryReadTable.readAlllibaryAndTableStruct();

      //初始化Velocity配置文件
      properties.setProperty("resource.loaders", "class");
      properties.setProperty("resource.loader.class.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
      properties.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
      properties.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
    } catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }


  /**
   * 生成文件
   * v1.0.0
   * @param packageAddress BuiderAbstract数组
   * @param templatepath   模板路径
   * @author C.c
   * @since 2023-04-04 08:47
   **/
//  public void createFile(List<FilePathAndClassName<BuiderAbstract>> packageAddress, String templatepath) {
//    Template tpl = Velocity.getTemplate(templatepath, String.valueOf(StandardCharsets.UTF_8));
//    packageAddress.forEach(filePathAndClassName -> {
//  String replace = templatepath.replace("\\", "/");
//  URL resource = this.getClass().getResource(replace);
//  String file = null;
//      if (resource != null) {
//    file = resource.getFile();
//  }
//      try {
//        VelocityContext context = new VelocityContext(filePathAndClassName.getBuildClass().buildClass());
//        PrintWriter pw = new PrintWriter(CREAT_ADDRESS + "\\" + filePathAndClassName.getClassFilePath());
//        tpl.merge(context, pw);
//        pw.flush();
//        pw.close();
//      } catch (FileNotFoundException e) {
//        throw new RuntimeException(e);
//      }
//    });
//  }


  /**
   * 生成文件
   * v1.1.0
   *
   * @param templatepath 模板路径
   * @param packageAddress BuiderAbstract数组

   * @author C.c
   * @since 2023-05-18 14:45
   **/
//  public void createFile(List<FilePathAndClassName<BuiderAbstract>> packageAddress, String templatepath) {
//
//    VelocityEngine ve = new VelocityEngine();
//    ve.init(properties);
//    packageAddress.forEach(filePathAndClassName -> {
//      Template t = ve.getTemplate(templatepath, String.valueOf(StandardCharsets.UTF_8));
//      VelocityContext context = new VelocityContext(filePathAndClassName.getBuildClass().buildClass());
//      try {
//        PrintWriter pw = new PrintWriter(CREAT_ADDRESS + "\\" + filePathAndClassName.getClassFilePath());
//        t.merge(context, pw);
//        pw.flush();
//        pw.close();
//      } catch (FileNotFoundException e) {
//        throw new RuntimeException(e);
//      }
//    });
//  }

  /**
   * 生成文件
   * v1.2.2
   *
   * @param templatepath   模板路径
   * @param packageAddress BuiderAbstract数组
   * @author C.c
   * @since 2023-05-18 14:45
   **/
  public void createFile(List<FilePathAndClassName<BuiderAbstract>> packageAddress, String templatepath) {

    packageAddress.forEach(buiderAbstractFilePathAndClassName -> {

      ClassPathResource cpr = new ClassPathResource(templatepath);
      InputStream inputStream = null;
      try {
        //获取模板文件
        inputStream = cpr.getInputStream();

        StringWriter writer = new StringWriter();
        IOUtils.copy(inputStream, writer, StandardCharsets.UTF_8.name());
        StringReader stringReader = new StringReader(writer.toString());

        //写入数据
        VelocityContext vcontext = new VelocityContext(buiderAbstractFilePathAndClassName.getBuildClass().buildClass());

        StringWriter w = new StringWriter();
        VelocityEngine velocity = new VelocityEngine();
        velocity.init(properties);
//        velocity.evaluate(vcontext, w, "Java_Auto_generate", writer.toString());
        velocity.evaluate(vcontext, w, "Java_Auto_generate", stringReader);


        PrintWriter pw = new PrintWriter(CREAT_ADDRESS + "\\" + buiderAbstractFilePathAndClassName.getClassFilePath());
        pw.println(w);
        pw.flush();
        pw.close();

      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    });
  }

  /**
   * 创建文件路径
   *
   * @param packageAddress 数组
   * @author C.c
   * @since 2023-04-04 08:51
   **/
  public void mkdirFile(List<FilePathAndClassName<BuiderAbstract>> packageAddress) {
    packageAddress.forEach(e -> {
      String filePath = e.getFilePath();
      String pathstr = CREAT_ADDRESS + "\\" + filePath;
      Path path = Paths.get(pathstr);
      try {
        Files.createDirectories(path);
      } catch (IOException ex) {
        //生成文件失败
        throw new RuntimeException(ex);
      }
    });
  }

  public void putPathAddress(String className, StringBuilder path) {
    StringBuilder targetPath = new StringBuilder(path);
    PATH_PACKAGE_MAP.put(className, targetPath.append(".").append(className).toString());
  }

  public String getPathAddress(String className) {
    return PATH_PACKAGE_MAP.get(className);
  }

  public List<LibaryProperties> getLibaryProperties() {
    try {
      reloadDatabase();
    } catch (SQLException e) {
      throw new RuntimeException(e);
    }
    return LIBARY_PROPERTIES;
  }

  public void build(List<FilePathAndClassName<BuiderAbstract>> filePathAndClassNames, String template) {
    mkdirFile(filePathAndClassNames);
    createFile(filePathAndClassNames, template);
  }

  public void reloadDatabase() throws SQLException {
    LibaryReadTable.reload();
    LIBARY_PROPERTIES = LibaryReadTable.readAlllibaryAndTableStruct();
  }
}
